#pragma once

#include <stx/core/encoding.hpp>

inline namespace stx
{
[[noreturn]] void startEventLoop(std::size_t const worker_thrd_cnt,
                                 std::string const s_thrd_tag);
[[noreturn]] void startEventLoop(std::size_t const worker_thrd_cnt);
[[noreturn]] void startEventLoop(std::string s_thrd_tag);
[[noreturn]] void startEventLoop();

void schedule(Task);

template<IsNonVoid Fn_,
         IsAnyType... Args_,
         IsAnyType R =
             std::invoke_result_t<std::decay_t<Fn_>, std::decay_t<Args_>...>>
inline Future<R> startAsyncTask(Fn_ fn, Args_&&... args)
{
    auto const sp_prom = std::make_shared<Promise<R>>();

    schedule(
        [sp_prom, MOVE(fn), DECAY_COPY_ARGS(args)] mutable
        {
            if constexpr (IsNonVoid<R>)
            {
                sp_prom->setValue(std::invoke(fn, std::move(args)...));
            }
            else
            {
                std::invoke(fn, std::move(args)...);
                sp_prom->setValue();
            }
        });

    co_return co_await sp_prom->getFuture();
}

/*
void demoTimerController()
{
    auto timer_ctler = TimerController{};
    startTimerTask(
        500ms, [] { print(123); }, timer_ctler);

    schedule(
        [=] mutable
        {
            sleepFor(5s);
            timer_ctler.stop();
        });
}
*/
enum class TimerState
{
    K_REPEATING,
    K_ONESHOT,
    K_CANCELED,
};

DEFINE_SAFE_BOOL(SbRepeating);

class TimerController final
{
    friend Future<> startTimerTask(Duration const  dur_initial_expiration,
                                   Duration const  dur_repeated_expiration,
                                   Task            fn_task,
                                   TimerController timer_ctler);

    friend Future<> startTimerTask(Duration const  dur_interval,
                                   Task            fn_task,
                                   TimerController timer_ctler);

private:
    std::shared_ptr<std::atomic<TimerState>> sp_timer_state_;

public:
    explicit TimerController(SbRepeating const sb_repeating = {});

    void                     cancel() noexcept;
    [[nodiscard]] TimerState getTimerState() const noexcept;
};

Future<> startTimerTask(Duration const  dur_initial_expiration,
                        Duration const  dur_repeated_expiration,
                        Task            fn_task,
                        TimerController timer_ctler);

Future<> startTimerTask(Duration const        dur_interval,
                        Task                  fn_task,
                        TimerController const timer_ctler);

Future<> startOneshotTimerTask(Duration const dur_interval, Task fn_task);

Future<> startRepeatingTimerTask(Duration const dur_interval, Task fn_task);

/*
Future<> startMyTimer(Duration const dur_interval)
{
	while (gTimerIsEnabled())
	{
	    co_await dur_interval;
		doSomething();
	}
}

int main()
{
	initPosixEnv();
	startMyTimer();
	startEventLoop();
}
*/
inline Future<> operator co_await(IsDurationLike auto const dur)
{
    return startOneshotTimerTask(dur, [] {});
}

template<IsRawTransferable T>
class AsyncLockFreeQueue final
{
    NonblockingLockFreeQueue<T> q_;
    EventFd                     efd_;

public:
    template<IsIdentical<T> U>
    void enqueue(U&& v)
    {
        q_.enqueue(FORWARD(v));
        this->efd_.notify();
    }

    Future<T> dequeue(Duration const dur_timeout)
    {
        auto v = T{};
        while (true)
        {
            if (q_.try_dequeue(v))
            {
                co_return v;
            }

            auto const fd_state = co_await wait(
                this->efd_.fd(), FdState::K_READABLE, dur_timeout);
            if (!isReadable(fd_state))
            {
                LOG_ERROR("Invalid fd_state: "sv,
                          this->efd_.fd(),
                          _I_,
                          fd_state,
                          dur_timeout.ms.count());
            }

            this->efd_.clear();
        }
    }
};
} // namespace stx